home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / news / inn1.000 / inn1.4sec-linux-src.tar / inn / innd / his.c < prev    next >
C/C++ Source or Header  |  1993-01-29  |  6KB  |  280 lines

  1. /*  $Revision: 1.21 $
  2. **
  3. **  History file routines.
  4. */
  5. #include "innd.h"
  6. #include "dbz.h"
  7.  
  8.  
  9. STATIC char    HIShistpath[] = _PATH_HISTORY;
  10. STATIC FILE    *HISwritefp;
  11. STATIC int    HISreadfd;
  12. STATIC int    HISdirty;
  13. STATIC int    HISincore = INND_DBZINCORE;
  14.  
  15.  
  16. /*
  17. **  Set up the history files.
  18. */
  19. void
  20. HISsetup()
  21. {
  22.     if (HISwritefp == NULL) {
  23.     /* Open the history file for appending formatted I/O. */
  24.     if ((HISwritefp = fopen(HIShistpath, "a")) == NULL) {
  25.         syslog(L_FATAL, "%s cant fopen %s %m", LogName, HIShistpath);
  26.         exit(1);
  27.     }
  28.     CloseOnExec((int)fileno(HISwritefp), TRUE);
  29.  
  30.     /* Open the history file for reading. */
  31.     if ((HISreadfd = open(HIShistpath, O_RDONLY)) < 0) {
  32.         syslog(L_FATAL, "%s cant open %s %m", LogName, HIShistpath);
  33.         exit(1);
  34.     }
  35.     CloseOnExec(HISreadfd, TRUE);
  36.  
  37.     /* Open the DBZ file. */
  38.     (void)dbzincore(HISincore);
  39.     (void)dbzwritethrough(1);
  40.     if (dbminit(HIShistpath) < 0) {
  41.         syslog(L_FATAL, "%s cant dbminit %s %m", HIShistpath, LogName);
  42.         exit(1);
  43.     }
  44.     }
  45. }
  46.  
  47.  
  48. /*
  49. **  Synchronize the in-core history file (flush it).
  50. */
  51. void
  52. HISsync()
  53. {
  54.     if (HISdirty) {
  55.     if (dbzsync()) {
  56.         syslog(L_FATAL, "%s cant dbzsync %m", LogName);
  57.         exit(1);
  58.     }
  59.     HISdirty = 0;
  60.     }
  61. }
  62.  
  63.  
  64. /*
  65. **  Close the history files.
  66. */
  67. void
  68. HISclose()
  69. {
  70.     if (HISwritefp != NULL) {
  71.     /* Since dbmclose calls dbzsync we could replace this line with
  72.      * "HISdirty = 0;".  Oh well, it keeps the abstraction clean. */
  73.     HISsync();
  74.     if (dbmclose() < 0)
  75.         syslog(L_ERROR, "%s cant dbmclose %m", LogName);
  76.     if (fclose(HISwritefp) == EOF)
  77.         syslog(L_ERROR, "%s cant fclose history %m", LogName);
  78.     HISwritefp = NULL;
  79.     if (close(HISreadfd) < 0)
  80.         syslog(L_ERROR, "%s cant close history %m", LogName);
  81.     HISreadfd = -1;
  82.     }
  83. }
  84.  
  85.  
  86. /*
  87. **  File in the DBZ datum for a Message-ID, making sure not to copy any
  88. **  illegal characters.
  89. */
  90. STATIC void
  91. HISsetkey(p, keyp)
  92.     register char    *p;
  93.     datum        *keyp;
  94. {
  95.     static BUFFER    MessageID;
  96.     register char    *dest;
  97.     register int    i;
  98.  
  99.     /* Get space to hold the ID. */
  100.     i = strlen(p);
  101.     if (MessageID.Data == NULL) {
  102.     MessageID.Data = NEW(char, i + 1);
  103.     MessageID.Size = i;
  104.     }
  105.     else if (MessageID.Size < i) {
  106.     RENEW(MessageID.Data, char, i + 1);
  107.     MessageID.Size = i;
  108.     }
  109.  
  110.     for (keyp->dptr = dest = MessageID.Data; *p; p++)
  111.     if (*p == HIS_FIELDSEP || *p == '\n')
  112.         *dest++ = HIS_BADCHAR;
  113.     else
  114.         *dest++ = *p;
  115.     *dest = '\0';
  116.  
  117.     keyp->dsize = dest - MessageID.Data + 1;
  118. }
  119.  
  120.  
  121. /*
  122. **  Get the list of files under which a Message-ID is stored.
  123. */
  124. char *
  125. HISfilesfor(MessageID)
  126.     char        *MessageID;
  127. {
  128.     static BUFFER    Files;
  129.     char        *dest;
  130.     datum        key;
  131.     datum        val;
  132.     long        offset;
  133.     register char    *p;
  134.     register int    i;
  135.  
  136.     /* Get the seek value into the history file. */
  137.     HISsetkey(MessageID, &key);
  138.     val = dbzfetch(key);
  139.     if (val.dptr == NULL || val.dsize != sizeof offset)
  140.     return NULL;
  141.  
  142.     /* Get space. */
  143.     if (Files.Data == NULL) {
  144.     Files.Size = BUFSIZ;
  145.     Files.Data = NEW(char, Files.Size);
  146.     }
  147.  
  148.     /* Copy the value to an aligned spot. */
  149.     for (p = val.dptr, dest = (char *)&offset, i = sizeof offset; --i >= 0; )
  150.     *dest++ = *p++;
  151.     if (lseek(HISreadfd, offset, SEEK_SET) == -1)
  152.     return NULL;
  153.  
  154.     /* Read the text until \n or EOF. */
  155.     for (Files.Used = 0; ; ) {
  156.     i = read(HISreadfd,
  157.         &Files.Data[Files.Used], Files.Size - Files.Used - 1);
  158.     if (i <= 0)
  159.         return NULL;
  160.     Files.Used += i;
  161.     Files.Data[Files.Used] = '\0';
  162.     if ((p = strchr(Files.Data, '\n')) != NULL) {
  163.         *p = '\0';
  164.         break;
  165.     }
  166.  
  167.     /* If we have half our buffer left, get more space. */
  168.     if (Files.Size - Files.Used < Files.Size / 2) {
  169.         Files.Size += BUFSIZ;
  170.         RENEW(Files.Data, char, Files.Size);
  171.     }
  172.     }
  173.  
  174.     /* Move past the first two fields -- Message-ID and date info. */
  175.     if ((p = strchr(Files.Data, HIS_FIELDSEP)) == NULL)
  176.     return NULL;
  177.     if ((p = strchr(p + 1, HIS_FIELDSEP)) == NULL)
  178.     return NULL;
  179.  
  180.     /* Translate newsgroup separators to slashes, return the fieldstart. */
  181.     for (dest = ++p; *p; p++)
  182.     if (*p == '.')
  183.         *p = '/';
  184.     return dest;
  185. }
  186.  
  187.  
  188. /*
  189. **  Have we already seen an article?
  190. */
  191. BOOL
  192. HIShavearticle(MessageID)
  193.     char    *MessageID;
  194. {
  195.     datum    key;
  196.     datum    val;
  197.  
  198.     HISsetkey(MessageID, &key);
  199.     val = dbzfetch(key);
  200.     return val.dptr != NULL;
  201. }
  202.  
  203.  
  204. /*
  205. **  Turn a history filename entry from slashes to dots.  It's a pity
  206. **  we have to do this.
  207. */
  208. STATIC void
  209. HISslashify(p)
  210.     register char    *p;
  211. {
  212.     register char    *last;
  213.  
  214.     for (last = NULL; *p; p++) {
  215.     if (*p == '/') {
  216.         *p = '.';
  217.         last = p;
  218.     }
  219.     else if (*p == ' ' && last != NULL)
  220.         *last = '/';
  221.     }
  222.     if (last)
  223.     *last = '/';
  224. }
  225.  
  226.  
  227. /*
  228. **  Write a history entry.
  229. */
  230. BOOL
  231. HISwrite(Data, paths)
  232.     ARTDATA        *Data;
  233.     char        *paths;
  234. {
  235.     static char        NOPATHS[] = "";
  236.     long        offset;
  237.     datum        key;
  238.     datum        val;
  239.     int            i;
  240.  
  241.     HISsetkey(Data->MessageID, &key);
  242.     if (paths != NULL && paths[0] != '\0')
  243.     HISslashify(paths);
  244.     else
  245.     paths = NOPATHS;
  246.  
  247.     offset = ftell(HISwritefp);
  248.     if (Data->Expires > 0)
  249.     i = fprintf(HISwritefp, "%s%c%ld%c%ld%c%ld%c%s\n",
  250.         key.dptr, HIS_FIELDSEP,
  251.         (long)Data->Arrived, HIS_SUBFIELDSEP, (long)Data->Expires,
  252.             HIS_SUBFIELDSEP, (long)Data->Posted, HIS_FIELDSEP,
  253.         paths);
  254.     else
  255.     i = fprintf(HISwritefp, "%s%c%ld%c%s%c%ld%c%s\n",
  256.         key.dptr, HIS_FIELDSEP,
  257.         (long)Data->Arrived, HIS_SUBFIELDSEP, HIS_NOEXP,
  258.             HIS_SUBFIELDSEP, (long)Data->Posted, HIS_FIELDSEP,
  259.         paths);
  260.     if (i == EOF || fflush(HISwritefp) == EOF) {
  261.     /* The history line is now an orphan... */
  262.     IOError("history");
  263.     syslog(L_ERROR, "%s cant write history %m", LogName);
  264.     return FALSE;
  265.     }
  266.  
  267.     /* Set up the database values and write them. */
  268.     val.dptr = (char *)&offset;
  269.     val.dsize = sizeof offset;
  270.     if (dbzstore(key, val) < 0) {
  271.     IOError("history database");
  272.     syslog(L_ERROR, "%s cant dbzstore %m", LogName);
  273.     return FALSE;
  274.     }
  275.  
  276.     if (++HISdirty >= ICD_SYNC_COUNT)
  277.     HISsync();
  278.     return TRUE;
  279. }
  280.